home *** CD-ROM | disk | FTP | other *** search
- # Source Generated with Decompyle++
- # File: in.pyc (Python 2.6)
-
- import gzip
- import string
- import tarfile
- import zlib
- from arfile import ArFile, ArError
- from changelog import Changelog
- from deb822 import Deb822
- DATA_PART = 'data.tar'
- CTRL_PART = 'control.tar'
- PART_EXTS = [
- 'gz',
- 'bz2']
- INFO_PART = 'debian-binary'
- MAINT_SCRIPTS = [
- 'preinst',
- 'postinst',
- 'prerm',
- 'postrm',
- 'config']
- CONTROL_FILE = 'control'
- CHANGELOG_NATIVE = 'usr/share/doc/%s/changelog.gz'
- CHANGELOG_DEBIAN = 'usr/share/doc/%s/changelog.Debian.gz'
- MD5_FILE = 'md5sums'
-
- class DebError(ArError):
- pass
-
-
- class DebPart(object):
- '''\'Part\' of a .deb binary package.
-
- A .deb package is considered as made of 2 parts: a \'data\' part
- (corresponding to the \'data.tar.gz\' archive embedded in a .deb) and a
- \'control\' part (the \'control.tar.gz\' archive). Each of them is represented
- by an instance of this class. Each archive should be a compressed tar
- archive; supported compression formats are: .tar.gz, .tar.bz2 .
-
- When referring to file members of the underlying .tar.gz archive, file
- names can be specified in one of 3 formats "file", "./file", "/file". In
- all cases the file is considered relative to the root of the archive. For
- the control part the preferred mechanism is the first one (as in
- deb.control.get_content(\'control\') ); for the data part the preferred
- mechanism is the third one (as in deb.data.get_file(\'/etc/vim/vimrc\') ).
- '''
-
- def __init__(self, member):
- self._DebPart__member = member
- self._DebPart__tgz = None
-
-
- def tgz(self):
- '''Return a TarFile object corresponding to this part of a .deb
- package.
-
- Despite the name, this method gives access to various kind of
- compressed tar archives, not only gzipped ones.
- '''
- if self._DebPart__tgz is None:
- name = self._DebPart__member.name
- if name.endswith('.gz'):
- gz = gzip.GzipFile(fileobj = self._DebPart__member, mode = 'r')
- self._DebPart__tgz = tarfile.TarFile(fileobj = gz, mode = 'r')
- elif name.endswith('.bz2'):
- self._DebPart__tgz = tarfile.open(fileobj = self._DebPart__member, mode = 'r:bz2')
- else:
- raise DebError("part '%s' has unexpected extension" % name)
- name.endswith('.gz')
- return self._DebPart__tgz
-
-
- def __normalize_member(fname):
- """ try (not so hard) to obtain a member file name in a form relative
- to the .tar.gz root and with no heading '.' """
- if fname.startswith('./'):
- fname = fname[2:]
- elif fname.startswith('/'):
- fname = fname[1:]
-
- return fname
-
- __normalize_member = staticmethod(__normalize_member)
-
- def has_file(self, fname):
- '''Check if this part contains a given file name.'''
- fname = DebPart._DebPart__normalize_member(fname)
- names = self.tgz().getnames()
- if not './' + fname in names:
- pass
- return fname in names
-
-
- def get_file(self, fname):
- '''Return a file object corresponding to a given file name.'''
- fname = DebPart._DebPart__normalize_member(fname)
-
- try:
- return self.tgz().extractfile('./' + fname)
- except KeyError:
- return self.tgz().extractfile(fname)
-
-
-
- def get_content(self, fname):
- '''Return the string content of a given file, or None (e.g. for
- directories).'''
- f = self.get_file(fname)
- content = None
- if f:
- content = f.read()
- f.close()
-
- return content
-
-
- def __iter__(self):
- return iter(self.tgz().getnames())
-
-
- def __contains__(self, fname):
- return self.has_file(fname)
-
-
- def has_key(self, fname):
- return self.has_file(fname)
-
-
- def __getitem__(self, fname):
- return self.get_content(fname)
-
-
-
- class DebData(DebPart):
- pass
-
-
- class DebControl(DebPart):
-
- def scripts(self):
- ''' Return a dictionary of maintainer scripts (postinst, prerm, ...)
- mapping script names to script text. '''
- scripts = { }
- for fname in MAINT_SCRIPTS:
- if self.has_file(fname):
- scripts[fname] = self.get_content(fname)
- continue
-
- return scripts
-
-
- def debcontrol(self):
- """ Return the debian/control as a Deb822 (a Debian-specific dict-like
- class) object.
-
- For a string representation of debian/control try
- .get_content('control') """
- return Deb822(self.get_content(CONTROL_FILE))
-
-
- def md5sums(self):
- """ Return a dictionary mapping filenames (of the data part) to
- md5sums. Fails if the control part does not contain a 'md5sum' file.
-
- Keys of the returned dictionary are the left-hand side values of lines
- in the md5sums member of control.tar.gz, usually file names relative to
- the file system root (without heading '/' or './'). """
- if not self.has_file(MD5_FILE):
- raise DebError("'%s' file not found, can't list MD5 sums" % MD5_FILE)
- self.has_file(MD5_FILE)
- md5_file = self.get_file(MD5_FILE)
- sums = { }
- for line in md5_file.readlines():
- (md5, fname) = line.rstrip('\r\n').split(None, 1)
- sums[fname] = md5
-
- md5_file.close()
- return sums
-
-
-
- class DebFile(ArFile):
- '''Representation of a .deb file (a Debian binary package)
-
- DebFile objects have the following (read-only) properties:
- - version debian .deb file format version (not related with the
- contained package version), 2.0 at the time of writing
- for all .deb packages in the Debian archive
- - data DebPart object corresponding to the data.tar.gz (or
- other compressed tar) archive contained in the .deb
- file
- - control DebPart object corresponding to the control.tar.gz (or
- other compressed tar) archive contained in the .deb
- file
- '''
-
- def __init__(self, filename = None, mode = 'r', fileobj = None):
- ArFile.__init__(self, filename, mode, fileobj)
- actual_names = set(self.getnames())
-
- def compressed_part_name(basename):
- candidates = [ '%s.%s' % (basename, ext) for ext in PART_EXTS ]
- parts = actual_names.intersection(set(candidates))
- if not parts:
- raise DebError('missing required part in given .deb (expected one of: %s)' % candidates)
- parts
- if len(parts) > 1:
- raise DebError('too many parts in given .deb (was looking for only one of: %s)' % candidates)
- len(parts) > 1
- return list(parts)[0]
-
- if INFO_PART not in actual_names:
- raise DebError("missing required part in given .deb (expected: '%s')" % INFO_PART)
- INFO_PART not in actual_names
- self._DebFile__parts = { }
- self._DebFile__parts[CTRL_PART] = DebControl(self.getmember(compressed_part_name(CTRL_PART)))
- self._DebFile__parts[DATA_PART] = DebData(self.getmember(compressed_part_name(DATA_PART)))
- self._DebFile__pkgname = None
- f = self.getmember(INFO_PART)
- self._DebFile__version = f.read().strip()
- f.close()
-
-
- def __updatePkgName(self):
- self._DebFile__pkgname = self.debcontrol()['package']
-
- version = property((lambda self: self._DebFile__version))
- data = property((lambda self: self._DebFile__parts[DATA_PART]))
- control = property((lambda self: self._DebFile__parts[CTRL_PART]))
-
- def debcontrol(self):
- ''' See .control.debcontrol() '''
- return self.control.debcontrol()
-
-
- def scripts(self):
- ''' See .control.scripts() '''
- return self.control.scripts()
-
-
- def md5sums(self):
- ''' See .control.md5sums() '''
- return self.control.md5sums()
-
-
- def changelog(self):
- ''' Return a Changelog object for the changelog.Debian.gz of the
- present .deb package. Return None if no changelog can be found. '''
- if self._DebFile__pkgname is None:
- self._DebFile__updatePkgName()
-
- for fname in [
- CHANGELOG_DEBIAN % self._DebFile__pkgname,
- CHANGELOG_NATIVE % self._DebFile__pkgname]:
- if self.data.has_file(fname):
- gz = gzip.GzipFile(fileobj = self.data.get_file(fname))
- raw_changelog = gz.read()
- gz.close()
- return Changelog(raw_changelog)
-
-
-
- if __name__ == '__main__':
- import sys
- deb = DebFile(filename = sys.argv[1])
- tgz = deb.control.tgz()
- print tgz.getmember('control')
-
-